package com.globalwave.pos.inventory.service;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.globalwave.common.exception.BusinessException;
import com.globalwave.pos.inventory.entity.ProductItem;
import com.globalwave.pos.inventory.entity.ProductItemSO;
import com.globalwave.pos.purchase.entity.PurchasesOrderLine;
import com.globalwave.pos.sale.entity.SalesOrder;
import com.globalwave.pos.sale.entity.SalesOrderLine;
import com.globalwave.system.entity.SessionUser;


/**
 * 库存模块对外接口
 * 
 * @author Virgil.Chen
 *
 */
@Service("inventoryBO")
@Scope("prototype")
@Transactional
public class InventoryBO extends InventoryBaseBO {
	
	private InventoryBalanceBO inventoryBalanceBO  ;
	private ProductItemBO productItemBO ;
	private InventoryTransactionBO inventoryTransactionBO ;
	
	
	public InventoryBO() {
		//super.warehouseCode = warehouseCode ;

	}


	/**
	 * 判断Order Line中的产品，是否可以销售，是否有足够的库存销售
	 * 
	 * @param itemSO 订单行，需要提供item number & quantity
	 * @throws Exception
	 */
	public ProductItem checkSalable(ProductItemSO itemSO) throws Exception {
		int orderQuantity = itemSO.getOrder_quantity() ;
		if (orderQuantity < 0) {
			throw new BusinessException("err.inv.quantity.lt.0");
		}
		
		
		Long saleDate = (long)SessionUser.get().getSale_date() * 1000000 ;
		
		String warehouseCode = itemSO.getWarehouse_code() ;
		
		ProductItemBO itemBo = getProductItemBO() ;
		//itemBo.get(orderLine.getItem_number()) ;
		itemBo.validateSalable(itemSO.getItem_number(), saleDate, itemSO.getPrice_percentage()) ;
		
		InventoryBalanceBO balanceBo = getInventoryBalanceBO(warehouseCode) ;

		Long stock_item_number = itemBo.get().getStock_item_number() ;
		//orderLine.setStock_item_number(stock_item_number) ;
		
		balanceBo.validateSalable(
				stock_item_number, 
				orderQuantity, 
				saleDate) ;
		// 状态判断
		
		return itemBo.get();
	}
	

	public void checkSalable(SalesOrderLine line) throws Exception {
		ProductItemSO so = new ProductItemSO() ;
		so.setItem_number(line.getItem_number()) ;
		so.setOrder_quantity(line.getOrder_quantity()) ;
		
		SalesOrder order = line.getSalesOrder() ;
		
		so.setPrice_percentage(order.getPrice_percentage()) ;
		so.setSale_date(order.getSale_date()) ;
		so.setWarehouse_code(order.getWarehouse_code()) ;
		
		line.setStock_item_number(checkSalable(so).getStock_item_number()) ;
	}
	

	public void checkShipable(SalesOrderLine line) throws Exception {
		ProductItemSO so = new ProductItemSO() ;
		so.setItem_number(line.getItem_number()) ;
		so.setOrder_quantity(line.getShipped_quantity()) ;
		
		SalesOrder order = line.getSalesOrder() ;
		
		so.setPrice_percentage(order.getPrice_percentage()) ;
		so.setSale_date(order.getSale_date()) ;
		so.setWarehouse_code(order.getWarehouse_code()) ;
		
		line.setStock_item_number(checkSalable(so).getStock_item_number()) ;
	}

	/**
	 * 判断Order Line中的产品，是否可以销售，是否有足够的库存销售
	 * 
	 * @param itemSO 订单行，需要提供item number & quantity
	 * @throws Exception
	 */
	public ProductItem checkPurchasable(ProductItemSO itemSO) throws Exception {
		
		int orderQuantity = itemSO.getOrder_quantity() ;
		if (orderQuantity < 0) {
			throw new BusinessException("err.inv.quantity.lt.0");
		}
		
		
		Long saleDate = (long)SessionUser.get().getSale_date() * 1000000 ;
		
		//String warehouseCode = itemSO.getWarehouse_code() ;
		
		ProductItemBO itemBo = getProductItemBO() ;
		//itemBo.get(orderLine.getItem_number()) ;
		itemBo.validateSalable(itemSO.getItem_number(), saleDate, itemSO.getPrice_percentage()) ;
		/*
		InventoryBalanceBO balanceBo = getInventoryBalanceBO(warehouseCode) ;

		Long stock_item_number = itemBo.get().getStock_item_number() ;
		//orderLine.setStock_item_number(stock_item_number) ;
		
		balanceBo.validateSalable(
				stock_item_number, 
				orderQuantity, 
				saleDate) ;
		// 状态判断
		*/
		return itemBo.get();
	}

	
	public void mortgage(SalesOrder order) throws Exception {
		//final List<OrderLinePO> orderLinesOrdered = reorder(orderLines) ;
		// for all lines, check & update it		

		this.warehouseCode = order.getWarehouse_code() ;
					
		for (SalesOrderLine line:order.getLines()) {
			mortgage(line) ;
		}
		
	}

	
	public void mortgage(SalesOrderLine line) throws Exception {
		//final List<OrderLinePO> orderLinesOrdered = reorder(orderLines) ;
		// for all lines, check & update it		

		this.checkSalable(line) ;

		this.warehouseCode = line.getSalesOrder().getWarehouse_code() ;
		this.getInventoryTransactionBO(warehouseCode).mortgage(line) ;
		
	}

	
	public void shipment(SalesOrder order) throws Exception {
		//final List<OrderLinePO> orderLinesOrdered = reorder(orderLines) ;
		// for all lines, check & update it		

		//this.warehouseCode = order.getWarehouse_code() ;
					
		for (SalesOrderLine line:order.getLines()) {
			shipment(line) ;
		}
		
	}

	
	public void shipment(SalesOrderLine line) throws Exception {
		//final List<OrderLinePO> orderLinesOrdered = reorder(orderLines) ;
		// for all lines, check & update it		

		this.checkShipable(line) ;
		
		this.warehouseCode = line.getSalesOrder().getWarehouse_code() ;
		this.getInventoryTransactionBO(this.warehouseCode).shipment(line) ;
		
	}
	
	public void replenishment(PurchasesOrderLine line) throws Exception {
		
		this.warehouseCode = line.getPurchasesOrder().getWarehouse_code() ;
		this.getInventoryTransactionBO(this.warehouseCode).replenishment(line) ;
	}
	
	public void cancel(SalesOrder orderHeader) throws Exception {
		getInventoryTransactionBO(null).cancel(orderHeader.getOid()) ;
	}
	
	private ProductItemBO getProductItemBO() {
		if (productItemBO == null) {
			productItemBO =  new ProductItemBO() ; 
		}
		return productItemBO ;
	}
	
	private InventoryBalanceBO getInventoryBalanceBO(String warehouse_code) {
		if (inventoryBalanceBO == null) {
		    inventoryBalanceBO =  new InventoryBalanceBO(warehouse_code) ;
		    inventoryBalanceBO.setJdbcDao(jdbcDao) ;
		} 
		return inventoryBalanceBO ;
	}
	
	private InventoryTransactionBO getInventoryTransactionBO(String warehouse_code) {
		if (inventoryTransactionBO == null) {
			inventoryTransactionBO =  new InventoryTransactionBO(warehouse_code) ;
			inventoryTransactionBO.setJdbcDao(jdbcDao) ;
		} 
		return inventoryTransactionBO ;
	}
}
